/**
 * @file Define the sales service
 * 
 * @author Steve Gao<gaofu@parllay.com>
 */
const async             = require('async');
const redisKey          = require('../redisKey');
const utils             = require('../utils');
const BaseService       = require('./base-service').BaseService;
const SystemServices    = require('../constants').SystemServices;

/**
 * The SalesService class is used for all functionalities about sales operations
 * 
 * @class SalesService
 * @param {ApplicationContext} context - The application context
 * 
 */
class SalesService extends BaseService {
    
    get userService() {
        return this.getSystemService(SystemServices.USER_SERVICE);
    }

    get wallService() {
        return this.getSystemService(SystemServices.WALL_SERVICE);
    }

    /**
     * Purchse productions
     * 
     * @name purchaseProductions
     * @param {String} userId - The userId of current session
     * @param {Number} planId - The selected plan id
     * @param {Number} itemCount - The count of items
     * @param {Object} params - The additonal information about the productions
     * @param {Function} parentCallback - The callback function
     * 
     * @returns {void}
     */
    purchaseProductions(userId, planId, item, itemCount, params, parentCallback) {
        var me = this;
        var itemType = typeof item;
        switch(itemType) {
        case 'object':
            if( item.length !== Number(itemCount.length)) {
                parentCallback({
                    success: false,
                    error: "所有购买的产品必须指定购买数量！"
                });
                return;
            }
            break;
        }
        this.acquireStorageClients({
            mysql: true
        }, function(clients) {
            var mysql = clients.mysql;
            var productionList = null;
            async.waterfall([
                function(callback) {
                    me.getProductionsByItemIds(mysql, item, (productions) => {
                        callback(null, productions);
                    });
                },
                function(productions, callback) {
                    productionList = productions;

                    switch(itemType) {
                    case 'string':
                        if(productions && productions.length === 1 && productions[0].plan_id !== planId) {
                            me.releaseStorageClients(clients);
                            parentCallback({
                                success: false,
                                error: '购买的产品不属于当前计划！'
                            });
                        } else if(productions && productions.length === 1) {
                            callback(null, productions);
                        } else {
                            me.releaseStorageClients(clients);
                            parentCallback({
                                success: false,
                                error: '系统中没有指定编号[' + item + ']的产品！'
                            });
                        }
                        break;
                    case 'object':
                        if(productions && productions.length === item.length) {
                            callback(null, productions);
                        } else {
                            me.releaseStorageClients(clients);
                            parentCallback({
                                success: false,
                                error: '系统中有些产品没有找到, 请确认产品[' + item.join(',') + ']!'
                            });
                        }
                        break;
                    }
                },
                function(productions, callback) {
                    switch(itemType) {
                        case 'string': {
                            switch(productions[0].handler) {
                                case 'realtime_update': {
                                    var currentDate = new Date();
                                    var startDate = new Date(params.start_date);
                                    var endDate = new Date(params.end_date);
                                    var count = (endDate - startDate) / (86400000);
                                    var wallId = params.wall_id;
                                    if(!wallId) {
                                        me.releaseStorageClients(clients); //此类代码需要重构
                                        parentCallback({
                                            success: false,
                                            error: '请选择要购买实时更新的朋友圈！'
                                        });
                                    } 
                                    else if (startDate < currentDate) {
                                        me.releaseStorageClients(clients); //此类代码需要重构
                                        parentCallback({
                                            success: false,
                                            error: '开始时间不能小于当前时间！'
                                        });
                                    } else if (endDate < startDate) {
                                        me.releaseStorageClients(clients);;
                                        parentCallback({
                                            success: false,
                                            error: '结束时间不能小于开始时间！'
                                        });
                                    } else if ( count !== Number(itemCount)) {
                                        me.releaseStorageClients(clients);;
                                        parentCallback({
                                            success: false,
                                            error: '购买数量有误，请重新选定时间范围！'
                                        });
                                    } else {
                                        callback(null, productions, Number(itemCount));
                                    }
                                }
                                break;
                            case 'plan': //暂时未实现
                                me.releaseStorageClients(clients);;
                                parentCallback({
                                    success: false,
                                    error: '暂时未实现此产品的购买！'
                                });
                                break;
                            }
                        }
                        break;
                        case 'object': //暂时未实现
                            me.releaseStorageClients(clients);
                            parentCallback({
                                success: false,
                                error: '暂时未实现此产品的购买！'
                            });
                            break;
                    }
                },
                function(productions, itemCounts, callback) {
                    switch(itemType) {
                        case 'string': {
                            switch(productions[0].handler) {
                                case 'realtime_update': {
                                    productions[0].extra_data = {
                                        start_date: params.start_date,
                                        end_date: params.end_date,
                                        wall_id: params.wall_id
                                    };
                                    productions[0].count = itemCounts;
                                }
                                break;
                                case 'plan':
                                me.releaseStorageClients(clients);
                                parentCallback({
                                    success: false,
                                    error: '暂时未实现此产品的购买！'
                                });
                                break; //暂未实现
                            }
                        }
                        break;
                        case 'object': //暂未实现
                            me.releaseStorageClients(clients);
                            parentCallback({
                                success: false,
                                error: '暂时未实现此产品的购买！'
                            });
                            break;
                    }

                    callback(null, productions)
                },
                function(productions, callback) { // 创建订单
                    me.createOrder(mysql, userId, productions, (result) => {
                        callback(null, result.orderId, result.amount);
                    });
                },
                function(orderId, amount, callback) { // 创建支付信息
                    var payments = [];
                    if(params.coupon) {
                        me.getCouponByCode(mysql, params.coupon, (coupons) => {
                            var result = {
                                success: true
                            };
                            var coupon = coupons[0];
                            if(coupons && coupons.length > 0) {
                                if (!coupon.is_redeemed) {
                                    result.success = false;
                                    result.error = '此代金券暂未生效，请联系销售人员！';
                                }

                                if (coupon.is_used) {
                                    result.success = false;
                                    result.error = '此代金券已使用，不能重复使用！';
                                }
                            } else {
                                result.success = false;
                                result.error = '系统中没有找到此代金券[' + params.coupon + ']！';
                            }
                            if(!result.success) {
                                me.rollbackOrder(mysql, orderId, (data) => {
                                    me.releaseStorageClients(clients);
                                    parentCallback(result);
                                });
                            } else {
                                var discountedAmount = amount;
                                switch(coupon.coupon_price_type) {
                                    case 'amount':
                                    discountedAmount -= coupon.coupon_price;
                                    break;
                                    case 'percentage':
                                    discountedAmount = discountedAmount * coupon.coupon_price;
                                    break;
                                }

                                discountedAmount = discountedAmount < 0 ? 0 : discountedAmount;

                                discountedAmount = Math.round(discountedAmount * 100) / 100;

                                payments.push({
                                    order_id: orderId,
                                    payment_type: 'coupon',
                                    amount: (amount - discountedAmount),
                                    transaction_data: coupon,
                                    status: 'done'
                                });

                                if(discountedAmount > 0) {
                                    payments.push({
                                        order_id: orderId,
                                        payment_type: 'alipay',
                                        amount: discountedAmount,
                                        transaction_data: null,
                                        status: 'paying'
                                    });
                                }

                                callback(null, orderId, payments);
                            }
                        });
                    } else {
                        payments.push({
                            order_id: orderId,
                            payment_type: 'alipay',
                            amount: amount,
                            transaction_data: null,
                            status: 'paying'
                        });
                        callback(null, orderId, payments)
                    }
                },
                function(orderId, payments, callback) {
                    var isDone = true;
                    var couponPayments = [];
                    var remainingAmount = 0;
                    payments.forEach(function(payment) {
                        isDone = isDone && (payment.status === 'done');
                    });

                    var functionChain = [];
                    payments.forEach(function(payment) {
                        if (payment.payment_type === 'coupon') {
                            couponPayments.push(payment);
                        }
                        if (payment.status === 'paying') {
                            remainingAmount += payment.amount;
                        }
                        functionChain.push(function(callback) {
                            mysql.query("INSERT INTO wall_sales_order_payments(order_id, payment_type, amount, transaction_data, status) VALUES(?,?,?,?,?)", [payment.order_id, payment.payment_type, payment.amount, JSON.stringify(payment.transaction_data), payment.status], function(error, result) {
                                callback(null);
                            });
                        });
                        
                    });

                    couponPayments.forEach(function(payment) {
                        functionChain.push(function(callback) {
                            mysql.query('UPDATE wall_marketing_coupons SET is_used = 1 WHERE id = ?', [payment.transaction_data.id], function(error, result) {
                                callback(null);
                            });
                        })
                    });

                    if (isDone) {
                        productionList.forEach(function(production) {
                            switch(production.handler) {
                                case 'realtime_update':
                                functionChain.push(function(callback) {
                                    me.wallService.saveWallRealTimeConfig(orderId, production.extra_data.wall_id, production.extra_data.start_date, production.extra_data.end_date, function(configId) {
                                        production.extra_data.realtime_config_id = configId;
                                        callback(null);
                                    });
                                });
                                functionChain.push(function(callback) {
                                    var extraData = JSON.stringify(production.extra_data);
                                    mysql.query('UPDATE wall_sales_order_items SET extra_data = ? WHERE order_id = ? AND product_id = ?', [extraData, orderId, production.id], function(error, result) {
                                        callback(null);
                                    });
                                })
                                break;
                                case 'plan':
                                me.Context.releaseMySQLClient(mysql);
                                parentCallback({
                                    success: false,
                                    error: '暂时未实现此产品的购买！'
                                });
                                break;
                            }
                        });

                        functionChain.push(function(callback) {
                            mysql.query('UPDATE wall_sales_orders SET status = ? WHERE id = ?', ['done', orderId], function(error, result) {
                                callback(null);
                            });
                        });

                        functionChain.push(function() {
                            me.releaseStorageClients(clients);
                            parentCallback({
                                success: true,
                                data: {
                                    status: 'done'
                                }
                            })
                        });
                    } else {

                        //TODO: 实现支付宝支付逻辑
                        functionChain.push(function(callback) {
                            var subject = "";
                            var description = "";
                            productionList.forEach((production) => {
                                switch(production.handler) {
                                    case 'realtime_update':
                                    subject += production.name + "(" + itemCount + "天)"
                                    description += "购买" + itemCount + "天实时更新(" + params.start_date + "~" + params.end_date + ")"   
                                    break;
                                    case 'plan':

                                    break;
                                }
                            });
                            var alipayURL = me.Context.buildAlipayURL(orderId, subject, description, remainingAmount);
                            var transaction_data = {
                                alipay_url: alipayURL
                            };
                            mysql.query("UPDATE wall_sales_order_payments SET transaction_data = ? WHERE order_id = ? AND payment_type = 'alipay' AND status = 'paying'", [JSON.stringify(transaction_data), orderId], function(error, result) {

                                callback(null, alipayURL);
                            });
                            
                        });
                        functionChain.push(function(alipayUrl) {
                            me.releaseStorageClients(clients);
                            parentCallback({
                                success: true,
                                data: {
                                    status: 'paying',
                                    amount: remainingAmount,
                                    alipay_url: alipayUrl // 这个链接是调用支付宝的API实现的
                                }
                            });
                        })
                        
                    }

                    async.waterfall(functionChain);
                }
            ]);
        }, function(message) {
            parentCallback({
                success: false,
                error: '系统内部错误，请稍后再试！'
            });
        });
    }

    /**
     * Get coupon information by coupon code
     * 
     * @name getCouponByCode
     * @param {MySQLConnection} mysql - The MySQL connection
     * @param {Number} id - The coupon id
     * @param {Function} parentCallback - The callback function
     * 
     * @returns {void}
     */
    getCouponByCode(mysql, id, parentCallback) {
        mysql.query('SELECT * FROM wall_marketing_coupons WHERE coupon_code = ?', [id], (error, result) => {
            parentCallback(result);
        });
    }

    /**
     * Get productions by production ids
     * 
     * @name getProductionsByItemIds
     * @param {MySQLConnection} mysql - The MySQL connection
     * @param {Number|Array} item - The id or ids
     * @param {Function} parentCallback - The callback function
     * 
     * @returns {void}
     */
    getProductionsByItemIds(mysql, item, parentCallback) {
        var sql = "";
        var params = [];
        if(typeof item === 'string') {
            sql = 'SELECT * FROM wall_plan_production_inventory WHERE id = ?';
            params.push(item);
        } else {
            sql = 'SELECT * FROM wall_plan_production_inventory WHERE id IN (?)';
            params.push(item.join(','));
        }

        mysql.query(sql, params, function(error, result) {
            parentCallback(result);
        });
    }

    /**
     * Create order for user
     * 
     * @name createOrder
     * @param {MySQLConnection} mysql - The MySQL Connection
     * @param {String} userId - The user id of current session
     * @param {Array} productions - The production list
     * @param {Function} parentCallback - The callback function
     * 
     * @returns {void}
     */
    createOrder(mysql, userId, productions, parentCallback) {
        var me = this;
        var amount = 0;
        productions.forEach(function(production) {
            amount += production.price * production.count;
        });
        async.waterfall([
            function(callback) {
                mysql.query('CALL sp_wall_createOrder(?, ?, ?)', [userId, amount, me.getApplicationConfiguration('self_service_user_id'), ], callback);
            },
            function(result, callback) {
                var data = {
                    orderId : result[0][0].orderId,
                    amount: amount
                };
                var functionChain = [];
                productions.forEach((production) => {
                    functionChain.push(function(callback) {
                        mysql.query('INSERT INTO wall_sales_order_items(order_id, product_id, name, price, count, extra_data) VALUES(?,?,?,?,?,?)', [data.orderId, production.id, production.name, production.price,  production.count, JSON.stringify(production.extra_data)], function(error, result) {
                            // Add log here
                            callback(null);
                        });
                    });
                });
                functionChain.push(function() {
                    parentCallback(data);
                });

                async.waterfall(functionChain);
            }
        ]);
    }
    /**
     * Rollback the order 
     * 
     * @name rollbackOrder
     * @param {MySQLConnection} mysql - The MySQL Connection
     * @param {String} orderId - The order's id
     * @param {Function} parentCallback - The callback function
     * 
     * @returns {void}
     */
    rollbackOrder(mysql, orderId, parentCallback) {
        var sql = "DELETE FROM wall_sales_order_items WHERE order_id = " + orderId + ";";
        sql += "DELETE FROM wall_sales_order_payments WHERE order_id = " + orderId + ";";
        sql += "DELETE FROM wall_sales_orders WHERE id = " + orderId + ";";

        mysql.query(sql, function(error, result) {
            parentCallback(result);
        });
    }

    /**
     * Finish the purchase by alipay
     * 
     * @name finishPurchase
     * @param {Object} alipayData - The data come from alipay
     * @param {String} type - The type of callback, the values are notify_data and return_data
     * @param {Function} parentCallback - The callback function
     * 
     * @returns {void}
     */
    finishPurchase(alipayData, type, parentCallback) {
        var me = this;
        async.waterfall([
            function(callback) {
                me.Context.verifyNotify(alipayData, function(result) {
                    if (!result.success) {
                        return parentCallback(result);
                    }
                    callback(null);
                });
            }, function(callback) {
                var tradeStatus = alipayData.trade_status;
                if(tradeStatus !== 'TRADE_SUCCESS') {
                    return parentCallback({
                        success: false,
                        error: '交易未完成'
                    });
                }

                async.parallel({
                    mysql: function(callback) {
                        me.Context.acquireMySQLClient(callback);
                    }
                }, function(error, result) {
                    if(error) {
                        return parentCallback({
                            success: false,
                            error: '系统内部错误，请稍后再试！'
                        });
                    }

                    var mysql = result.mysql;

                    async.waterfall([
                        function(callback) {
                            mysql.query("SELECT * FROM wall_sales_order_payments WHERE payment_type = 'alipay' AND order_id = ?", [alipayData.out_trade_no], function(error, payments) {
                                if(error) {
                                    me.Context.releaseMySQLClient(mysql);
                                    parentCallback({
                                        success: false,
                                        error: '系统内部错误，请稍后再试！'
                                    });
                                } else {
                                    callback(null, payments);
                                }
                            });
                        }, function(payments, callback) {
                            var functionChain = [];
                            payments.forEach(function(payment) {
                                functionChain.push(function(callback1) {
                                    var paymentId = payment.id;
                                    var transactionData = JSON.parse(payment.transaction_data || '{}');
                                    transactionData[type] = alipayData;
                                    mysql.query('UPDATE wall_sales_order_payments SET transaction_data = ? WHERE id = ?', [JSON.stringify(transactionData), paymentId], function(error, result) {
                                        callback1(null);
                                    });
                                });
                                
                            });
                            functionChain.push(function() {
                                callback(null);
                            });
                            async.waterfall(functionChain);
                        }, function(callback) {
                            mysql.query("SELECT * FROM wall_sales_order_payments WHERE payment_type = 'alipay' AND order_id = ? AND status = 'paying'", [alipayData.out_trade_no], function(error, result) {
                                if(error) {
                                    me.Context.releaseMySQLClient(mysql);
                                    parentCallback({
                                        success: false,
                                        error: '系统内部错误，请稍后再试！'
                                    });
                                } else {
                                    callback(null, result);
                                }
                            });
                        }, function(payments, callback) {
                            if(payments && payments.length > 0) {
                                mysql.query('SELECT wppi.handler, wsoi.id, wsoi.order_id, wsoi.name, wsoi.extra_data FROM wall_plan_production_inventory wppi INNER JOIN wall_sales_order_items wsoi ON wsoi.product_id = wppi.id WHERE wsoi.order_id = ?', [alipayData.out_trade_no], function(error, productions) {
                                    if (error) {
                                        me.Context.releaseMySQLClient(mysql);
                                        parentCallback({
                                            success: false,
                                            error: '系统内部错误，请稍后再试！'
                                        });
                                    } else {
                                        callback(null, productions);
                                    }
                                });
                            } else {
                                me.Context.releaseMySQLClient(mysql);
                                parentCallback({
                                    success: true,
                                    data: true
                                });
                            }
                        }, function(productions, callback) {
                            if(productions && productions.length > 0) {
                                callback(null, productions);
                            } else {
                                me.Context.releaseMySQLClient(mysql);
                                parentCallback({
                                    success: true,
                                    data: true
                                })
                            }
                        }, function(productions, callback) {
                            var functionChain = [];
                            productions.forEach(function(production) {
                                var extraData = JSON.parse(production.extra_data || '{}');
                                switch(production.handler) {
                                    case 'realtime_update':
                                        functionChain.push(function(callback) {
                                            me.wallService.saveWallRealTimeConfig(production.order_id, extraData.wall_id, extraData.start_date, extraData.end_date, function(configId) {
                                                extraData.realtime_config_id = configId;
                                                callback(null);
                                            });
                                        });
                                        functionChain.push(function(callback) {
                                            mysql.query('UPDATE wall_sales_order_items SET extra_data = ? WHERE id = ?', [JSON.stringify(extraData), production.id], function(error, result) {
                                                callback(null);
                                            });
                                        });
                                    break;
                                    case 'plan':
                                    me.Context.releaseMySQLClient(mysql);
                                    parentCallback({
                                        success: false,
                                        error: '购买的产品不存在！'
                                    })
                                    break;
                                }
                            });

                            functionChain.push(function() {
                                callback(null);
                            });
                            async.waterfall(functionChain);
                        }, function(callback) {
                            var sql = "UPDATE wall_sales_order_payments SET status = 'done' WHERE order_id = " + alipayData.out_trade_no + " AND payment_type = 'alipay';";
                            sql += "UPDATE wall_sales_orders SET status = 'done' WHERE id = " + alipayData.out_trade_no + ";";

                            mysql.query(sql, function(error, result) {
                                me.Context.releaseMySQLClient(mysql);
                                parentCallback({
                                    success: true,
                                    data: true
                                });
                            });
                        }
                    ]);
                });
            }
        ])
    }
}

exports.SalesService = SalesService